#pragma once

#include <iostream>
#include <string>
#include <pthread.h>
#include <fstream>
#include <sys/types.h>
#include <sys/socket.h>
#include <vector>
#include <sstream>
#include <map>
#include <cstring>
#include <errno.h>
#include <algorithm>
#include <unistd.h>

#include "Socket.hpp" // 包含Socket.hpp

// 声明全局log对象和wwwroot路径，它们将在HttpServer.cc中定义
extern std::string g_wwwroot_base_path;
void log_message(const std::string& msg); // 声明日志函数

static const int defaultport = 8888;
const std::string homepage = "vsGame.html";
const std::string sep = "\r\n";

// MIME类型映射表
const std::map<std::string, std::string> mime_types = {
    {".html", "text/html; charset=utf-8"},
    {".htm", "text/html; charset=utf-8"},
    {".css", "text/css; charset=utf-8"},
    {".js", "text/javascript; charset=utf-8"},
    {".txt", "text/plain; charset=utf-8"},
    {".jpg", "image/jpeg"},
    {".jpeg", "image/jpeg"},
    {".png", "image/png"},
    {".gif", "image/gif"},
    {".svg", "image/svg+xml; charset=utf-8"},
    {".ttf", "font/ttf"},
    {".woff", "font/woff"},
    {".woff2", "font/woff2"},
    {".ico", "image/x-icon"},
    {".json", "application/json; charset=utf-8"}};

class HttpServer;

struct ThreadData
{
public:
    ThreadData(int fd, HttpServer *ts)
        : sockfd(fd), httpsvr(ts)
    {
    }

    int sockfd;
    HttpServer *httpsvr;
};

class HttpRequest
{
public:
    void Deserialize(std::string req)
    {
        // 移除 static 关键字，现在 buffer_ 是 HttpRequest 类的成员
        buffer_ += req;

        size_t pos;
        while ((pos = buffer_.find(sep + sep)) != std::string::npos) // 查找完整的报头结束标志 \r\n\r\n
        {
            // 分离报头行
            size_t line_end = buffer_.find(sep);
            while (line_end != std::string::npos && line_end < pos) {
                std::string temp = buffer_.substr(0, line_end);
                req_header.push_back(temp);
                buffer_.erase(0, line_end + sep.size());
                line_end = buffer_.find(sep);
            }
            // 移除报头和空行
            buffer_.erase(0, pos + (sep + sep).size());
            break; // 找到一个完整的报头就处理
        }
        // req_text 将包含报头之后的所有内容 (可能是请求体)
        req_text = buffer_;
        buffer_.clear(); // 处理完一个请求后清空缓冲区，避免下次 Deserialize 累积旧数据
    }

    void Parse()
    {
        if (req_header.empty())
        {
            file_path = "invalid_file_path"; // 统一无效路径标识
            return;
        }

        std::stringstream s(req_header[0]);
        s >> method >> url >> http_version;

        // 移除URL中的查询参数
        size_t query_pos = url.find('?');
        if (query_pos != std::string::npos)
        {
            url = url.substr(0, query_pos);
        }

        // 处理URL中可能包含的多余"/wwwroot"（解决路径重复问题）
        const std::string wwwroot_in_url_segment = "/wwwroot";
        size_t wwwroot_pos_in_url = url.find(wwwroot_in_url_segment);
        if (wwwroot_pos_in_url == 0 && url.length() > wwwroot_in_url_segment.length())
        {
            url = url.substr(wwwroot_in_url_segment.size());
        }

        // 确保URL以'/'开头，以便与g_wwwroot_base_path正确拼接
        if (url.empty() || url[0] != '/')
        {
            url = "/" + url;
        }

        std::vector<std::string> possible_paths;

        if (url == "/")
        {
            possible_paths.push_back(g_wwwroot_base_path + "/" + homepage);
        }
        else
        {
            std::string direct_path = g_wwwroot_base_path + url;
            possible_paths.push_back(direct_path);

            size_t last_dot_pos = url.find_last_of('.');
            size_t last_slash_pos = url.find_last_of('/');
            if (last_dot_pos == std::string::npos || (last_slash_pos != std::string::npos && last_dot_pos < last_slash_pos))
            {
                possible_paths.push_back(direct_path + ".html");
            }
        }

        file_path = "invalid_file_path";
        for (const auto &path : possible_paths)
        {
            std::ifstream test(path);
            if (test.good())
            {
                file_path = path;
                break;
            }
        }
        // log_message("DEBUG: Parsed Request -> Method: " + method + ", URL: " + url + ", FilePath: " + file_path);
    }

public:
    std::vector<std::string> req_header;
    std::string req_text;
    std::string method;
    std::string url;
    std::string http_version;
    std::string file_path;

private: // 添加私有成员变量
    std::string buffer_; // 每个 HttpRequest 实例拥有独立的请求数据缓冲区
};

class HttpServer
{
public:
    HttpServer(uint16_t port = defaultport)
        : port_(port)
    {
    }

    bool Start()
    {
        listensock_.Socket();
        listensock_.Bind(port_);
        listensock_.Listen();

        while (true)
        {
            std::string clientip;
            uint16_t clientport;
            int sockfd = listensock_.Accept(&clientip, &clientport);
            if (sockfd < 0)
            {
                // Accept内部已记录错误或正常退出，这里继续循环即可
                continue;
            }

            pthread_t tid;
            ThreadData *td = new ThreadData(sockfd, this);
            if (pthread_create(&tid, nullptr, ThreadRun, td) != 0)
            {
                log_message("ERROR: Failed to create thread for client " + clientip + ":" + std::to_string(clientport) + ": " + std::string(strerror(errno)));
                close(sockfd); // 创建线程失败，关闭套接字
                delete td;
            }
            else
            {
                // log_message("INFO: Thread created for client " + clientip + ":" + std::to_string(clientport));
            }
        }
    }

    static std::string getMimeType(const std::string &file_path)
    {
        if (file_path.empty() || file_path == "invalid_file_path")
        {
            return "text/html; charset=utf-8";
        }

        size_t dot_pos = file_path.find_last_of('.');
        if (dot_pos == std::string::npos || dot_pos == file_path.length() - 1)
        {
            return "application/octet-stream";
        }

        std::string ext = file_path.substr(dot_pos);
        std::transform(ext.begin(), ext.end(), ext.begin(), ::tolower);

        auto it = mime_types.find(ext);
        std::string mime = (it != mime_types.end()) ? it->second : "application/octet-stream";
        return mime;
    }

    static std::string ReadFileContent(const std::string &file_path)
    {
        std::ifstream in(file_path, std::ios::binary);
        if (!in.is_open())
        {
            log_message("ERROR: Failed to open file for reading: " + file_path + ": " + std::string(strerror(errno)));
            return "";
        }

        in.seekg(0, std::ios_base::end);
        std::streamsize len = in.tellg();
        in.seekg(0, std::ios_base::beg);

        std::string content;
        if (len > 0)
        {
            content.resize(static_cast<size_t>(len));
            in.read(&content[0], len);
        } else {
            // log_message("INFO: File is empty or could not determine size: " + file_path);
        }

        in.close();
        return content;
    }

    static std::string getCSPHeader()
    {
        return "default-src 'self'; "
               "style-src 'self' 'unsafe-inline'; "
               "script-src 'self' 'unsafe-inline' 'unsafe-eval'; "
               "img-src 'self' data:; "
               "font-src 'self'; "
               "frame-ancestors 'none';";
    }

    static void HandlerHttp(int sockfd, HttpServer *httpsvr)
    {
        try
        {
            char buffer[10240];
            ssize_t n = recv(sockfd, buffer, sizeof(buffer) - 1, 0);
            if (n <= 0)
            {
                if (n == 0) {
                    log_message("INFO: Client disconnected (sockfd: " + std::to_string(sockfd) + ")");
                } else { // n < 0
                    log_message("WARNING: recv failed for sockfd " + std::to_string(sockfd) + ": " + std::string(strerror(errno)));
                }
                close(sockfd);
                return;
            }

            buffer[n] = '\0'; // 确保接收到的数据是null结尾的

            HttpRequest req;
            req.Deserialize(buffer);
            req.Parse();
            
            bool file_exists_and_read = (req.file_path != "invalid_file_path");
            std::string text;

            if (file_exists_and_read)
            {
                text = ReadFileContent(req.file_path);
                file_exists_and_read = !text.empty(); // 再次检查文件内容是否为空
                if (!file_exists_and_read) {
                    log_message("WARNING: File content is empty or failed to read: " + req.file_path);
                }
            }

            if (!file_exists_and_read)
            {
                text = "<html><body><h1>404 Not Found</h1><p>请求的资源不存在: " + req.url + "</p></body></html>";
                log_message("INFO: 404 Not Found for URL: " + req.url);
            }
            else
            {
                // log_message("INFO: Serving file: " + req.file_path);
            }

            std::string response_line = file_exists_and_read ? "HTTP/1.1 200 OK\r\n" : "HTTP/1.1 404 Not Found\r\n";
            std::string response_header;

            response_header += "Content-Type: " + getMimeType(req.file_path) + "\r\n";
            response_header += "Content-Length: " + std::to_string(text.size()) + "\r\n";
            response_header += "Connection: close\r\n";
            response_header += "X-Content-Type-Options: nosniff\r\n";
            response_header += "Content-Security-Policy: " + getCSPHeader() + "\r\n";

            if (file_exists_and_read)
            {
                size_t dot_pos = req.file_path.find_last_of('.');
                if (dot_pos != std::string::npos && dot_pos < req.file_path.length() - 1)
                {
                    std::string ext = req.file_path.substr(dot_pos);
                    if (ext == ".html" || ext == ".htm")
                    {
                        response_header += "Cache-Control: public, max-age=180\r\n";
                    }
                    else
                    {
                        response_header += "Cache-Control: public, max-age=31536000, immutable\r\n";
                    }
                }
                else
                {
                    response_header += "Cache-Control: public, max-age=31536000, immutable\r\n";
                }
            }
            else
            {
                response_header += "Cache-Control: no-store\r\n";
            }

            std::string blank_line = "\r\n";
            std::string response = response_line + response_header + blank_line + text;

            ssize_t sent = send(sockfd, response.c_str(), response.size(), 0);
            if (sent < 0)
            {
                log_message("WARNING: Failed to send response to sockfd " + std::to_string(sockfd) + ": " + std::string(strerror(errno)));
            }
            else if (static_cast<size_t>(sent) != response.size())
            {
                log_message("WARNING: Sent " + std::to_string(sent) + " bytes, but response size was " + std::to_string(response.size()) + " for sockfd " + std::to_string(sockfd));
            }

            close(sockfd);
        }
        catch (const std::out_of_range &e)
        {
            log_message("ERROR: Out of range exception in HandlerHttp for sockfd " + std::to_string(sockfd) + ": " + e.what());
            close(sockfd);
        }
        catch (const std::exception &e)
        {
            log_message("ERROR: Standard exception in HandlerHttp for sockfd " + std::to_string(sockfd) + ": " + e.what());
            close(sockfd);
        }
        catch (...)
        {
            log_message("ERROR: Unknown exception in HandlerHttp for sockfd " + std::to_string(sockfd));
            close(sockfd);
        }
    }

    static void *ThreadRun(void *args)
    {
        ThreadData *td = static_cast<ThreadData *>(args);
        pthread_detach(pthread_self());

        try
        {
            HandlerHttp(td->sockfd, td->httpsvr);
        }
        catch (...)
        {
            log_message("ERROR: Exception caught in ThreadRun, closing sockfd " + std::to_string(td->sockfd));
            close(td->sockfd);
        }

        delete td;
        return nullptr;
    }

    ~HttpServer()
    {
        listensock_.Close();
        log_message("INFO: HttpServer destroyed, listensock closed.");
    }

private:
    Sock listensock_;
    uint16_t port_;
};
